#include<mysql/mysql.h>
#include<stdio.h>
#include<string>
#include<string.h>
#include<stdlib.h>
#include<list>
#include<pthread.h>
#include<iostream>
#include"sql_connection_pool.h"

using namespace std;

connection_pool::connection_pool(){
    m_CurConn=0;
    m_FreeConn=0;//当前已使用和当前空闲连接数置为0
}

connection_pool *connection_pool::GetInstance(){
    static connection_pool connPool;//静态局部变量在第一次进入函数时初始化，之后所有调用都会跳过初始化
    return &connPool;//C++11标注保证静态局部变量的初始化是线程安全的
}

//构造初始化
void connection_pool::init(string url, string User, string PassWord, string DBName, int Port, int MaxConn, int close_log){
    m_url=url;//主机地址
    m_Port=Port;//数据库端口号
    m_User=User;//登录数据库用户名
    m_PassWord=PassWord;//登录数据库密码
    m_DatabaseName=DBName;//使用数据库名
    m_close_log=close_log;//日志开关

    for(int i=0;i<MaxConn;i++){
        MYSQL *con=mysql_init(NULL);//初始化数据库连接指针
        if(con==NULL){
            LOG_ERROR("MySQL Error");//日志记录MySQL错误
            exit(1);//终止程序，返回状态码1
        }
        //string下的c_str()函数 返回一个以\0结尾的char类型的数组
        //建立连接
        con=mysql_real_connect(con,url.c_str(),User.c_str(),PassWord.c_str(),DBName.c_str(),Port,NULL,0);
        //                         服务器地址， 用户名       密码              数据库名      端口号，不使用unix套接字，无特殊客户端标志
        if(con==NULL){
            LOG_ERROR("MySQL Error");
            exit(1);
        }
        connList.push_back(con);
        ++m_FreeConn;
    }
    reserve=sem(m_FreeConn);//初始化信号量
    m_MaxConn=m_FreeConn;
}

//当有请求时，从数据库连接池中返回一个可用连接，更新使用和空闲连接数
MYSQL* connection_pool::GetConnection(){
    MYSQL* con=NULL;
    if(0==connList.size()){//若连接池的大小为0，返回空
        return NULL;
    }
    reserve.wait();
    lock.lock();
    con=connList.front();
    connList.pop_front();
    --m_FreeConn;
    ++m_CurConn;
    lock.unlock();
    return con;
}

//释放当前使用的连接
bool connection_pool::ReleaseConnection(MYSQL*con){
    if(NULL==con){
        return false;
    }
    lock.lock();
    connList.push_back(con);
    ++m_FreeConn;
    --m_CurConn;
    lock.unlock();
    reserve.post();
    return true;
}

//销毁数据库连接池
void connection_pool::DestroyPool(){
    lock.lock();
    if(connList.size()>0){
        for(auto it=connList.begin();it!=connList.end();it++){
            MYSQL*con=*it;
            mysql_close(con);
        }
        m_CurConn=0;
        m_FreeConn=0;
        connList.clear();
    }
    lock.unlock();
}

//当前空闲的连接数
int connection_pool::GetFreeConn(){
    return this->m_FreeConn;
}

//销毁连接池
connection_pool::~connection_pool(){
    DestroyPool();
}

//使用RAII机制获取连接
connectionRAII::connectionRAII(MYSQL **SQL,connection_pool *connPool){
    *SQL=connPool->GetConnection();//获取数据库连接
    conRAII=*SQL;//将连接传递
    poolRAII=connPool;//传递连接池
}

//使用RAII机制释放连接
connectionRAII::~connectionRAII(){
    poolRAII->ReleaseConnection(conRAII);
}